﻿#include "../../x/draw/draw.h"
#include "../../interface/IBackground.h"

namespace swui
{
	void IBackground::_background_border_directory_fill(_ctlInterior::drawInfo* info)
	{
		MoveToEx(info->hDC, getLeft(), getTop(), NULL);
		if(getBkBorderDirectory() & 0x08)
			LineTo(info->hDC, getRight() - 1, getTop());
		else MoveToEx(info->hDC, getRight() - 1, getTop(), NULL);
		if(getBkBorderDirectory() & 0x04)
			LineTo(info->hDC, getRight() - 1, getBottom() - 1);
		else MoveToEx(info->hDC, getRight() - 1, getBottom() - 1, NULL);
		if(getBkBorderDirectory() & 0x02)
			LineTo(info->hDC, getLeft(), getBottom() - 1);
		else MoveToEx(info->hDC, getLeft(), getBottom() - 1, NULL);
		if(getBkBorderDirectory() & 0x01)
			LineTo(info->hDC, getLeft(), getTop());
	}
	void common_gradient_draw_x(_ctlInterior::drawInfo* info, 
		ctlDoubleColor border, ctlDoubleColor fill, bool drawborder, int dir, ctlRect rc);
	void IBackground::_background_redraw(_ctlInterior::drawInfo* info, bool gdip)
	{
		if(!isBackgroundEnabled()) return;
		//绘制背景图像
		if(getBackImageIndex() != imageNull)
			draw_image(getRect(), info, getBackImage(), getBackImageRepeat(), getBackImageAlpha(), 
			getBackImageMaskEnable(), getBackImageMaskColor(), _eventTrans.getMajorInfo()->tempAlpha);
		//画笔样式映射表
		const int BorderStyleMap[] = { PS_SOLID, PS_DASH, PS_DOT, 
			PS_DASHDOT, PS_DASHDOTDOT, PS_NULL };
		const DashStyle BorderStyleMapp[] = { DashStyleSolid, DashStyleDash, 
			DashStyleDot, DashStyleDashDot, DashStyleDashDotDot, DashStyleSolid };
		
		bool bfboolean = (getBkBorderColor() & 0xff000000) == 0xff000000;
		bool bkgradientsolid = true;
		if(isBackgroundFillGradientEnabled() && 
			(getBkFillColor() >> 24) != (getBkFillGradientEnd() >> 24))
			bkgradientsolid = false;
		bool bkempty = getBkFillStyle() == fillStyle::empty;
		if(bfboolean && bkgradientsolid && !gdip 
			&& (getBkFillStyle() == fillStyle::solid || bkempty))
		{
			//边框不透明、背景不透明且为 solid 填充
			if((getBkFillColor() & 0xff000000) == 0xff000000)
			{
				//背景不透明
				HBRUSH hBrush = CreateSolidBrush(MAKE_SYSTEM_RGB(getBkFillColor() & 0xffffff));
				HPEN hPen = CreatePen(BorderStyleMap[static_cast<unsigned>(getBkBorderStyle())],
					1, MAKE_SYSTEM_RGB(getBkBorderColor() & 0xffffff));
				HGDIOBJ hOldPen = SelectObject(info->hDC, hPen);
				RECT rc;
				SetRect(&rc, getLeft(), getTop(), getRight(), getBottom());
				if(isBackgroundFillGradientEnabled()
					&& getBkFillColor() != getBkFillGradientEnd())
				{
					//背景为渐变
					if(!bkempty)
					{
						common_gradient_draw_x(info, ctlDoubleColor(0, 0), 
							ctlDoubleColor(getBkFillColor(), getBkFillGradientEnd()), 
							false, GRADIENT_FILL_RECT_V, getRect());
					}
					if(getBkBorderDirectory() != 0x0f)
					{
						_background_border_directory_fill(info);
					} else {
						SelectObject(info->hDC, GetStockObject(NULL_BRUSH));
						Rectangle(info->hDC, rc.left, rc.top, rc.right, rc.bottom);
					}
				} else {
					//背景不是渐变
					if(getBkBorderDirectory() != 0x0f)
					{
						rc.top += 1;
						if(!bkempty) FillRect(info->hDC, &rc, hBrush);
						_background_border_directory_fill(info);
					} else {
						HGDIOBJ oldBrush = SelectObject(info->hDC, 
							bkempty ? GetStockObject(NULL_BRUSH) : hBrush);
						Rectangle(info->hDC, rc.left, rc.top, rc.right, rc.bottom);
						SelectObject(info->hDC, oldBrush);
					}
				}
				SelectObject(info->hDC, hOldPen);
				DeleteObject(hPen);
				DeleteObject(hBrush);
			} else {
				//背景带透明度
				HPEN hPen = CreatePen(BorderStyleMap[static_cast<unsigned>(getBkBorderStyle())],
					1, MAKE_SYSTEM_RGB(getBkBorderColor() & 0xffffff));
				HGDIOBJ hOldPen = SelectObject(info->hDC, hPen);
				
				if(!bkempty)
				{
					_eventTrans.getMajorInfo()->tempAlpha.require(getWidth(), getHeight());
					HDC alphaDC = _eventTrans.getMajorInfo()->tempAlpha.getDC();
					BLENDFUNCTION bf = { 0 };
					bf.BlendOp = AC_SRC_OVER;
					bf.SourceConstantAlpha = getBkFillColor() >> 24;
					if(isBackgroundFillGradientEnabled()
						&& getBkFillColor() != getBkFillGradientEnd())
					{
						//有渐变
						_ctlInterior::drawInfo ninfo = *info;
						ninfo.hDC = alphaDC;
						common_gradient_draw_x(&ninfo, ctlDoubleColor(0, 0), 
							ctlDoubleColor(getBkFillColor(), getBkFillGradientEnd()), 
							false, GRADIENT_FILL_RECT_V, 
							ctlRect(0, 0, getWidth(), getHeight()).inflate(1, 1));
					} else {
						//无渐变
						RECT rc;
						SetRect(&rc, 0, 0, getWidth() - 2, getHeight() - 2);
						HBRUSH hBrush = CreateSolidBrush(MAKE_SYSTEM_RGB(getBkFillColor()));
						FillRect(alphaDC, &rc, hBrush);
						DeleteObject(hBrush);
					}
					AlphaBlend(info->hDC, getLeft() + 1, getTop() + 1, getWidth() - 2, getHeight() - 2, 
						alphaDC, 0, 0, getWidth() - 2, getHeight() - 2, bf);
				}
				_background_border_directory_fill(info);
				SelectObject(info->hDC, hOldPen);
				DeleteObject(hPen);
			}
		} else {
			std::shared_ptr<Brush> hBrush = nullptr;
			if(isBackgroundFillGradientEnabled())
				hBrush = decltype(hBrush)(new LinearGradientBrush(
				Point(getLeft(), getTop() - 1), Point(getLeft(), getBottom() + 1), 
				MAKE_COLOR32(getBkFillColor()), MAKE_COLOR32(getBkFillGradientEnd())));
			else if(static_cast<unsigned>(getBkFillStyle()) >= static_cast<unsigned>(fillStyle::solid))
				hBrush = decltype(hBrush)(new SolidBrush(MAKE_COLOR32(getBkFillColor())));
			else hBrush = decltype(hBrush)(new HatchBrush(
				static_cast<HatchStyle>(getBkFillStyle()), 
				MAKE_COLOR32(getBkFillColor()), MAKE_COLOR32(getBkHatchColor())));

			Pen hPen(MAKE_COLOR32(getBkBorderColor()));
			hPen.SetDashStyle(static_cast<DashStyle>(
				BorderStyleMapp[static_cast<unsigned>(getBkBorderStyle())]));
			Graphics* graphics = reinterpret_cast<Graphics*>(info->graphics);
			
			if(getBkFillStyle() != fillStyle::empty)
				graphics->FillRectangle(hBrush.get(), getLeft(), getTop(), getWidth() - 1, getHeight() - 1);
			if(getBkBorderStyle() != borderStyle::empty
				&& getBkBorderDirectory() != 0x00)
			{
				if(getBkBorderDirectory() != 0x0f)
				{
					if(getBkBorderDirectory() & 0x08)
						graphics->DrawLine(&hPen, Point(getLeft(), getTop()), Point(getRight() - 1, getTop()));
					if(getBkBorderDirectory() & 0x04)
						graphics->DrawLine(&hPen, Point(getRight() - 1, getTop()), Point(getRight() - 1, getBottom() - 1));
					if(getBkBorderDirectory() & 0x02)
						graphics->DrawLine(&hPen, Point(getRight() - 1, getBottom() - 1), Point(getLeft(), getBottom() - 1));
					if(getBkBorderDirectory() & 0x01)
						graphics->DrawLine(&hPen, Point(getLeft(), getBottom() - 1), Point(getLeft(), getTop()));
				} else {
					graphics->DrawRectangle(&hPen, getLeft(), getTop(), getWidth() - 1, getHeight() - 1);
				}
			}
		}
		if(getForeImageIndex() != imageNull)
			draw_image(getRect(), info, getForeImage(), getForeImageRepeat(), getForeImageAlpha(), 
			getForeImageMaskEnable(), getForeImageMaskColor(), _eventTrans.getMajorInfo()->tempAlpha);
	}
}